package com.javaspeak.designpatterns.go4.structural.flyweight;

import java.util.ArrayList;
import java.util.List;

import com.javaspeak.designpatterns.go4.creational.builder.Dimension;

/**
 * CanvasElements are added to this canvas and then rendered to System.out
 *
 * @author John Dickerson
 */
public class CanvasImpl implements Canvas {

    private List<CanvasElement> canvasElements = new ArrayList<CanvasElement>();


    /**
     * Works out the dimension of the Canvas required to accomodate all the
     * Canvas Elements
     *
     * @param canvasElements  CanvasElements which will be added to the Canvas
     *
     * @return the Dimension of the Canvas
     */
    private Dimension getCanvasDimension( List<CanvasElement> canvasElements ){

        int height = 0;
        int width = 0;

        for ( CanvasElement canvasElement : canvasElements ){

            int shapeLength =
                canvasElement.getShape().points.length +
                    canvasElement.getYcoordinate();

            if (  shapeLength > height ){

                height = shapeLength;
            }

            int shapeWidth =
                canvasElement.getShape().points[ 0 ].length +
                    canvasElement.getXcoordinate();

            if ( shapeWidth > width ){

                width = shapeWidth;
            }
        }

        return new Dimension( width, height );
    }


    /**
     * Renders a CanvasElement on the canvas. This involves copying the pixels
     * of the shape onto the canvasPixels array.
     *
     * @param canvasElement
     * @param canvasPixels
     */
    private void render( CanvasElement canvasElement, int[][]canvasPixels ){

        int[][] points = canvasElement.getShape().points;

        for ( int y=0; y<points.length; y++ ) {

            for ( int x=0; x<points[ y ].length; x++ ) {

                canvasPixels[ y + canvasElement.getYcoordinate() ]
                    [ x + canvasElement.getXcoordinate() ] =
                        points[ y ][ x ];
            }
        }

    }


    /**
     * Paints the canvas pixels to System.out
     *
     * @param canvasPixels The canvas pixels to paint to System.out
     */
    private void paint( int[][] canvasPixels ){

        for ( int y=0; y<canvasPixels.length; y++ ){

            StringBuilder sb = new StringBuilder();

            for ( int x=0; x<canvasPixels[ y ].length; x++ ){

                if ( canvasPixels[ y ][ x ] == 1 ) {

                    sb.append( canvasPixels[ y ][ x ] );
                }
                else {

                    sb.append( " " );
                }
            }

            System.out.println( sb.toString() );
        }
    }


    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.structural.flyweight.Canvas#
     *      addCanvasElement(com.javaspeak.designpatterns.go4.structural.
     *          flyweight.CanvasElement)
     */
    @Override
    public void addCanvasElement(CanvasElement canvasElement) {

        canvasElements.add( canvasElement );
    }


    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.structural.flyweight.Canvas#render()
     */
    @Override
    public void render() {

        Dimension canvasDimension = getCanvasDimension( canvasElements );

        int[][] canvasPixels =
           new int[ canvasDimension.getHeight() ][ canvasDimension.getWidth() ];

        for ( CanvasElement canvasElement : canvasElements ){

            render( canvasElement, canvasPixels );
        }

        paint( canvasPixels );
    }
}
